已經過了 21 天,終於要進入 Vuex 相關的章節。
在開始寫 code 之前,先分享一個 Vue 核心成員 Chris Fritz 今年的演講影片,
介紹了 Vue 的七個少為人知的小技巧,看完真的收穫不少。
而今天會用到這個演講介紹的一個小技巧,幫助專案的 Vuex module 綁定(Module Registration)
影片連結: 7 Secret Patterns Vue Consultants Don’t Want You to Know
今天用到的是影片中介紹的第三點(從12:49)開始。
懶得看影片就讓我來簡單介紹一下怎麼輕鬆優化使用 Vuex Module
首先這個小技巧不限於在 Nuxt 應用中使用。
讓我們先建立好綁定 Vuex 所需的目錄結構:
上面可以看到建立了三個檔案:
import camelCase from 'lodash/camelCase'
const requireModule = require.context('.', false, /\.js$/)
const modules = {}
requireModule.keys().forEach(fileName => {
// Don't register this file as a Vuex module
if (fileName === './index.js') return
const moduleName = camelCase(
fileName.replace(/(\.\/|\.js)/g, '')
)
modules[moduleName] = {
namespaced: true,
...requireModule(fileName)
}
})
export default modules
第一行可以看到我們引用了 lodash 的 camelCase,之前的篇章已經有引入 lodash。
而核心的部分主要是使用 require.context 引入所有 ./modules 目錄底下除了 index.js 的 Vuex modules,
並且利用 requireModule.keys().forEach
主動為所有 module 加上 namespaced: true
的屬性。
經過了上面 modules/index.js 的綁定後,
store/index.js 就可以寫得像下面這樣簡潔:
import Vuex from 'vuex'
import modules from '@/store/modules'
const createStore = () => {
return new Vuex.Store({
modules
})
}
export default createStore
有了 Module Registration 之後,
就不必再為了新增 module 而修改 store/index.js。
介紹完 Module Registration 後,
接著開發使用 firebase 的服務 authentication 來串接登入功能。
用 firebase 登入非常容易,這邊將功能拆分為三個 actions:
請看程式碼:
import { auth } from '@/services/fireinit.js'
export const state = {
user: null
}
export const mutations = {
setUser (state, payload) { state.user = payload }
}
export const actions = {
signInWithEmail ({ commit }, payload) {
return auth.signInWithEmailAndPassword(payload.email, payload.password)
.then(user => user)
},
signOut ({ commit }) {
return auth.signOut()
.then(() => {
commit('setUser', null)
})
},
signInAuto ({ commit }) {
return new Promise((resolve, reject) => {
auth.onAuthStateChanged(user => {
if (user) {
commit('setUser', user)
}
resolve(user)
})
})
}
}
上面程式碼可以看到,
第一行引入了 fireinit.js
import { auth } from '@/services/fireinit.js'
還記得這是上一篇所完成的套件對吧?
fireinit 只是簡單的將 firebase 的 auth 做簡單的包裝。
auth.signInWithEmailAndPassword
應該都很直覺就不多解釋了。
記得已經在第 12 天 已經建立過所有需要的頁面,但是還沒有切版呢
已經有了 firebase authentication 的功能,
就差一個介面來登入。
這邊就不提供申請帳號的功能,因為畢竟只有作者自己能編輯。
登入的驗證一樣是透過前天介紹的 simple-vue-validator。
這邊的切版簡單使用了 Vuetify 的 v-text-field,
完全不必再寫任何一行 CSS。
解釋:
首先引入 SimpleVueValidation 並使用 conservative
模式,
這個模式是被動的驗證,必須等到使用者按下登入按鈕後,才會真正第一次執行驗證,
並在第一次驗證後模式自動切換為即時驗證。
另外 data 中的 error 用來顯示非同步的登入錯誤訊息,
而這邊可能錯誤原因為帳號密碼輸入錯誤。
import Vue from 'vue'
import SimpleVueValidation from 'simple-vue-validator'
const Validator = SimpleVueValidation.Validator
Vue.use(SimpleVueValidation, { mode: 'conservative' })
export default {
layout: 'admin',
data: vm => ({
email: '',
password: '',
error: false,
}),
validators: {
email: value => Validator.value(value).required().email(),
password: value => Validator.value(value).required()
},
methods: {
signIn () {
this.$validate()
.then(success => {
if (success) {
this.$store.dispatch('auth/signInWithEmail', {
email: this.email,
password: this.password
})
.then(data => {
if (data.status === 'success') {
this.error = false
this.$router.push('/admin')
} else {
this.email = ''
this.password = ''
this.error = true
this.$refs.email.focus()
this.validation.reset()
}
})
}
})
}
}
}
之前在第 11 篇已經將 layouts admin 切版完,
現在只需要新增自動登入的功能,以及將未登入的狀態導頁至登入頁。
export default {
beforeCreate () {
this.$store.dispatch('auth/signInAuto')
.then(user => {
user
? this.$router.push('/admin')
: this.$router.push('/admin/signIn')
})
},
methods: {
signOut () {
this.$store.dispatch('auth/signOut')
.then(() => {
this.$router.push('/admin/signIn')
})
}
}
}
這邊只需在 beforeCreate
執行 action(auth/signInAuto
),
並判斷要導頁至哪裡。
登出功能更只要執行 action(auth/signOut
),並導頁。
用了 Vuetify 後,不只是切版變得容易,
用了 simple-vue-validator 後,更是可以輕鬆快速搞定表單驗證。
登入畫面:
輸入密碼:
simple-vue-validator 驗證:
非同步驗證 Email 或密碼錯誤:
登入成功:
自動導頁到 admin 首頁,
並且可以看到右下 module/auth 的 state.user 已成功從 null 變成 object。
指令:
git clone -b 022-sign-in-out-auto --single-branch https://github.com/hunterliu1003/blog.git
cd blog
npm install
npm run dev
# localhost:8787/admin/signIn